<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>03-对象</title>
</head>
<script src="./js/browser.js"></script>
<script type="text/babel">
    /*
     *  对象的结构赋值
     *   对象属性没有次序，所以变量名与属性同名才能取到正确值。
     */
    var {bar,foo} ={"bar":1,"foo0":2}
    console.log({bar,foo})  //{bar: 1, foo: undefined}  找不到的是undefined

    //如果变量名与属性名不一致，必须写成下面的形式：
    var {foo:baz} = {"foo":"aaa"};
    console.log(baz);  //aaa,类似数组，键就相当于数组的索引。

    let obj={"first":"hello","last":"world"};
    let {first:f,last:l}=obj;
    console.log(f,l) //hello world

    // 下面的代码中，let命令下面的圆括号是必须的，否则会报错。解析器首先把他当做代码块，而不是赋值语句：
    let fooo;
    ({fooo} = {"fooo":1});
    console.log(fooo);  //1 let声明，下面赋值

    //对象的解构也可以设置默认值，支持嵌套：
    var {x=3} = {};
    console.log(x);  //3
    var {x,y=5} = {x:1};
    console.info(x,y)  //1 5
    var {x:y=3} = {x:5};
    console.info(y);  //5

    //默认值生效的条件是 对象的属性值严格等于undefined。
    var {x=3} = {x:undefined};
    console.info(x);  //3
    //对于已经声明的变量解构赋值，要带上圆括号：
    var x;
    ({x} = {x:1})
    console.info(x); //1
    //对象的解构赋值，可以很方便的将现有对象上的方法，赋值到某个变量：
    let {log,sin,cos} = Math;
    console.log(log,sin,cos);  //获取Math对象上的方法并赋值。
    //由于数组本质上是特殊的对象，所以可以对数组进行对象属性的解构：
    var arr = [1,2,3];
    var {0:first,[arr.length-1]:last} = arr;
    console.info(first,last);   //1 3


    //属性的遍历
    //1.使用Object.keys()遍历， 返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含Symbol属性).
    let obj1 = {'0':'a','1':'b','2':'c'};

    Object.keys(obj1).forEach(function(key){
        console.log(key,obj1[key]); // 0 a; 1 b; 2 c
    });

    //2、使用for..in..遍历   循环遍历对象自身的和继承的可枚举属性(不含Symbol属性)
    for (let i in obj1){
        console.log(i,":",obj1[i])  //0 : a ; 1 : b;  2 : c
    }

    // for (let i of obj1){  //obj1[Symbol.iterator] is not a function    for..of不能循环对象
    //     console.log(i,":",obj1[i])
    // }

    //3、使用Object.getOwnPropertyNames(obj)遍历,返回一个数组,本身不包含对象的 Symbol 属性，只包含字符串属性
    Object.getOwnPropertyNames(obj1).forEach(key=>{
        console.log(key,obj1[key]) //0 a;1 b;2 c
        return obj1;
    })

    //.4、Object.getOwnPropertySymbols(obj),返回一个数组,包含对象自身的所有Symbol属性.
    let obj4={};
    let am=Symbol("a");
    let bm=Symbol.for("b")

    obj4[am]="localSymbol";
    obj4[bm]="globalSymbol"

    let objectSymbols=Object.getOwnPropertySymbols(obj4);
    console.log(objectSymbols.length) //2
    console.log(objectSymbols) //[Symbol(a), Symbol(b)]
    console.log(objectSymbols[0]) //Symbol(a)

   // 5.Reflect.ownKeys(obj),返回一个数组,包含对象自身的所有属性,不管属性名是Symbol或字符串,也不管是否可枚举.
    const object1 = {
        property1: 42,
        property2: 13
    };
    let array2 = ["a","b","c"];
    console.log(Reflect.ownKeys(object1));  //["property1", "property2"]
    console.log(Reflect.ownKeys(array2));//["0", "1", "2", "length"]

   // 6.Reflect.enumerate(obj),返回一个Iterator对象,遍历对象自身的和继承的所有可枚举属性(不含Symbol属性),与for ... in 循环相同.(已废弃)


    //对象的方法
    //浅（引用）拷贝：共用同一内存地址,你改值我也变
    //深拷贝：深拷贝即创建新的内存地址保存值(互不影响)
    //Object.assign()： 通过复制一个或多个对象来创建一个新的对象。
    // Object.assign()拷贝的是属性值,假如源对象的属性值是一个对象的引用，那么它也只指向那个引用
    // 注意，Object.assign 不会跳过那些值为 null 或 undefined 的源对象

    //这是对象的浅拷贝:共同用一个值
    const target={a:1,b:2}
    const source={b:4,c:5}
    target.a=555
    const returnedTarget=Object.assign(target,source);
    console.log(returnedTarget)  //{a: 1, b: 4, c: 5}

    //这是对象的深拷贝:新建内存地址
    //Object.assign({},srcObj);得到的新对象为‘深拷贝’；如果属性值为对象或其它引用类型，那对于这个对象而言其实是浅拷贝的
    //Object.assign({}, src1, src2); 对于scr1和src2之间相同的属性是直接覆盖的，如果属性值为对象，是不会对对象之间的属性进行合并
    let obj10={a:0,b:{c:0}};
    let obj20=Object.assign({},obj10)
    console.log(JSON.stringify(obj20)); // { a: 0, b: { c: 0}}

    obj10.a=1
    console.log(JSON.stringify(obj10))  //{"a":1,"b":{"c":0}}
    console.log(JSON.stringify(obj20))  //{"a":0,"b":{"c":0}}

    obj20.a=2
    console.log(JSON.stringify(obj10)) //{"a":1,"b":{"c":0}}
    console.log(JSON.stringify(obj20)) //{"a":2,"b":{"c":0}}

    obj20.b.c = 3;
    console.log(JSON.stringify(obj10)); // { a: 1, b: { c: 3}}
    console.log(JSON.stringify(obj20)); // { a: 2, b: { c: 3}}




    //Object.create()方法创建一个新对象，使用现有的对象来提供新创建的对象的__proto__。
    const person={
        isHuman:false,
        printIntroduction:function () {
            console.log(`My name is ${this.name},Am I human?${this.isHuman}`)
        }
    };
    const me=Object.create(person);

    me.name="Matthew";
    me.isHuman=true;
    me.printIntroduction();
    //用 Object.create实现类式继承
    //Shape-父类
    function Shape() {
        this.x=0;
        this.y=0
    }
    //父类的方法
    Shape.prototype.move=function (x,y) {
        this.x+=x;
        this.y+=y
    }
    //Rectangle -子类
    function Rectangle() {
        Shape.call(this)   //call  super constructor  call继承构造函数
    }
    //子类继承父类
    Rectangle.prototype=Object.create(Shape.prototype);
    Rectangle.prototype.constructor=Rectangle;

    let rect=new Rectangle();

    console.log('Is rect an instance of Rectangle?',rect  instanceof Rectangle)  //true
    console.log('Is rect an instance of Shape?', rect instanceof Shape); // true
    rect.move(1,1)
    


</script>
<body>

</body>
</html>